package com.bungarus.busi;

import com.bungarus.codec.protobuf.MessageProtobuf;
import com.bungarus.model.BungarusClientException;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.EventLoopGroup;

import java.util.concurrent.atomic.AtomicInteger;

/**
 *
 * Created by tang on 2018/11/29.
 */
public interface BaseClient {
    /**
     * get netty channel connected to remote node
     * @return a connected netty channel
     */
    Channel getChannel();

    /**
     * get id of remote connected node (server)
     * @return id
     */
    int getRemoteNodeId();

    /**
     * start to run the client
     * @param connectionFrom the cluster tag of the remote node to which the client connects
     * @throws BungarusClientException
     */
    void run(String connectionFrom) throws BungarusClientException;

    /**
     * connect to the remote node
     * @param index the index which indicates the specific node
     * @param eventLoop the thread pool client uses to connect remote node and processes the inbound / outbound messages
     * @throws BungarusClientException
     */
    void connect(AtomicInteger index, EventLoopGroup eventLoop) throws BungarusClientException;

    /**
     * connect to the next remote node. The client must have a remote node list. In certain scenario, such as the remote node
     * has been halted, the client must connect to the next remote node.
     * @param eventLoopGroup the thread pool client uses to connect remote node and processes the inbound / outbound messages
     * @throws BungarusClientException
     */
    void connectNextNode(EventLoopGroup eventLoopGroup) throws BungarusClientException;

    /**
     * reload or refresh the remote node list.
     * @param eventLoopGroup the thread pool client uses to connect remote node and processes the inbound / outbound messages
     */
    void reLoadRemoteServers(EventLoopGroup eventLoopGroup);

    /**
     *
     * @param msg
     * @param clusterTag
     * @throws BungarusClientException
     */
    default void sendMessage(MessageProtobuf.Message msg, String clusterTag) throws BungarusClientException {
        sendMessage(msg, clusterTag, null);
    }

    /**
     * send message to connected remote node
     * @param msg message to be sent
     * @param clusterTag the cluster tag of the remote node to which the client connects
     * @param forAck netty handler context for responding the message sender
     * @throws BungarusClientException
     */
    void sendMessage(MessageProtobuf.Message msg, String clusterTag, ChannelHandlerContext forAck) throws BungarusClientException;

    /**
     * save the failed sending message
     * @param failedMsg failed message
     */
    void saveTryFailedMessage(MessageProtobuf.Message failedMsg);

    /**
     * close the connection
     */
    void close();

    default boolean isShuttingDown() {
        return false;
    }
}
